Interactive Graphics

Packages loaded for this talk

library(ggplot2)
library(plotly)
library(ggiraph)
library(highcharter)
library(rCharts) # ramnathv/rCharts
library(leaflet)
library(tibble)
library(dplyr)
library(tidyr)
library(crosstalk)
library(DT)

Why Interactive Graphics?

  • Because it’s fun

  • Because it’s cool

  • Because it allows a new dimension of conveying results

  • Because a collaborator asked

Packages in R Covered (at least in part)

  • plotly - framework for interactive plotting (covered a lot)

  • ggiraph - R package that creates interactive ggplot graphs using D3 and other frameworks

  • highcharter - wraps JS framework Highcharts

  • rCharts - interactive javascript visualizations from R using a familiar lattice style plotting interface

    • Interfaces polychart, Morris, NVD3, xCharts, Highcharts, Leaflet, Rickshaw
    • https://github.com/ramnathv/rCharts

Packages not covered

:::

  • rbokeh - another framework for interactive plotting

  • leaflet - great for interactive maps

  • rayshader - interactive 3D maps/plots/ggplot2s

  • d3heatmap - interactive heatmamps

  • threejs - 3D scatterplots

:::

How to build an interactive graphic

Many cases you know how to build a ggplot2 object

May want to “interactive” it up

Many times you will hit roadblocks or limitations

Toy Cars

We’re going to be using the toyest data, mtcars ! But we want the car names

(cars <- as_tibble(mtcars) %>% 
    rownames_to_column(var = "car") %>% 
    separate(car, into = c("make", "blah"), sep = " ", remove = FALSE, extra = "merge") %>% 
    select(make, car, everything()) %>% 
    select(-blah))
# A tibble: 32 × 13
   make  car     mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
   <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1 1     1      21       6  160    110  3.9   2.62  16.5     0     1     4     4
 2 2     2      21       6  160    110  3.9   2.88  17.0     0     1     4     4
 3 3     3      22.8     4  108     93  3.85  2.32  18.6     1     1     4     1
 4 4     4      21.4     6  258    110  3.08  3.22  19.4     1     0     3     1
 5 5     5      18.7     8  360    175  3.15  3.44  17.0     0     0     3     2
 6 6     6      18.1     6  225    105  2.76  3.46  20.2     1     0     3     1
 7 7     7      14.3     8  360    245  3.21  3.57  15.8     0     0     3     4
 8 8     8      24.4     4  147.    62  3.69  3.19  20       1     0     4     2
 9 9     9      22.8     4  141.    95  3.92  3.15  22.9     1     0     4     2
10 10    10     19.2     6  168.   123  3.92  3.44  18.3     1     0     4     4
# ℹ 22 more rows

Scatterplot

Weight (in tons) vs miles per gallon (MPG)

(ggplot(cars, aes(wt, mpg)) +
    geom_point())

Scatterplot (a little better)

(p <- ggplot(cars, aes(wt, mpg)) +
    geom_point() +
    xlab("Weight (in tons)") + 
    ylab("Miles Per Gallon (MPG)") + 
    theme_bw(base_size = 22))

Interactive Points (plotly)

plotly::ggplotly turns gg objects to plotly objects!

ggplotly(p)

Interactive Points (plotly)

Does a lot of the geoms

ggplotly(p + geom_line())

Customize Hover Over Things

plotly_button_config = function(fig,
                                buttons = c("toImage",
                                            "resetViews"),
                                displaylogo = FALSE,
                                displayModeBar = TRUE) {
  buttons = as.list(buttons)
  buttons = list(buttons)
  fig %>%
    plotly::config(modeBarButtons = buttons,
                   displaylogo = displaylogo,
                   displayModeBar = displayModeBar)
}

Interactive Points (plotly)

plotly_button_config(ggplotly(p))

More Interaction!

g = ggplot(cars, aes(x = factor(cyl), y = hp)) + 
  geom_boxplot(outlier.shape = NA)
ggplotly(g)

Interaction works with colour

gcol = ggplot(cars, aes(x = hp, y = mpg, colour = factor(cyl))) + 
  geom_point() +
  guides(colour = "none") +
  geom_smooth(se = FALSE) 
ggplotly(gcol)

Interaction (still) works with facets

ggplotly(gcol + facet_wrap(~ factor(cyl)))

Use Plotly interface directly (faster), uses formula syntax!

https://plotly.com/r/plotly-fundamentals/ is a great resource for starting (maybe 2 hours?)

Screenshot of Plotly webpage for fundamentals of plotting.

Use Plotly interface directly

Uses pipes not +. Main function is plot_ly (guesses type). Treats variable types as continuous if numbers.

cars %>% 
  plot_ly(x = ~ hp, y = ~mpg, color = ~ cyl)
No trace type specified:
  Based on info supplied, a 'scatter' trace seems appropriate.
  Read more about this trace type -> https://plotly.com/r/reference/#scatter
No scatter mode specifed:
  Setting the mode to markers
  Read more about this attribute -> https://plotly.com/r/reference/#scatter-mode

Put the type in though

And can do factor on the fly like normal formulas.

cars %>% 
  plot_ly(x = ~ hp, y = ~mpg, color = ~ factor(cyl), type = "scatter", mode = "markers")

Multiple types are with + (but in quotes)

cars %>% 
  plot_ly(x = ~ hp, y = ~mpg, color = ~ factor(cyl), type = "scatter", mode = "markers+lines")

It plots in order it sees

cars %>% 
  arrange(hp, mpg) %>% 
  plot_ly(x = ~ hp, y = ~mpg, color = ~ factor(cyl), type = "scatter", mode = "markers+lines")

Use Plotly interface directly

Can do very basic things.

plot_ly(x = c(1, 2, 3), y = c(1, 3, 2), type = 'bar') %>% 
  layout(title = 'A Plotly Figure',
         plot_bgcolor='#e5ecf6', 
         xaxis = list( 
           zerolinecolor = '#ffff', 
           zerolinewidth = 2, 
           gridcolor = 'ffff'), 
         yaxis = list( 
           zerolinecolor = '#ffff', 
           zerolinewidth = 2, 
           gridcolor = 'ffff')) 

Lot of add_* functions

cars %>% 
  plot_ly(x = ~ hp, y = ~mpg, color = ~ factor(cyl), type = "scatter") %>% 
  add_lines()
No scatter mode specifed:
  Setting the mode to markers
  Read more about this attribute -> https://plotly.com/r/reference/#scatter-mode

Lot of add_* functions

  cars %>% 
    plot_ly(x = ~ cyl, y = ~mpg, type = "box") %>% 
  add_markers()

Jitter

(jplot <- cars %>% 
  plot_ly(x = ~ cyl, y = ~mpg, type = "box") %>% 
  add_boxplot(jitter = 0.3, boxpoints = "all"))

How do we know that parameter?

Lots of different options. Has pros/cons vs. ggplot2.

?plotly::schema
# traces -> boxplot -> attributes -> boxpoints 

Plotly can do … a lot

# volcano is a numeric matrix that is in base R
(vplot <- plot_ly(z = ~volcano) %>% add_surface())

Plotly can do … a lot

(miniplot <- plotly::plot_ly() %>% 
  add_trace(x = c(1, 2, 3), y = c(4, 3, 2), mode='lines') %>% 
  add_trace(x = c(20, 30, 40), y = c(30, 40, 50), 
            xaxis='x2', yaxis='y2', mode='lines') %>%  # new axis
  layout(xaxis2 = list(domain = c(0.6, 0.95), anchor='y2'), # anchor based on axis
         yaxis2 = list(domain = c(0.6, 0.95), anchor='x2')))

Can do subplots

subplot(jplot, jplot, nrows = 2, margin = 0.05)

Some things don’t merge nicely

subplot(jplot, vplot, nrows = 2,  margin = 0.05)

Some things don’t merge nicely

subplot(jplot, vplot, nrows = 2,  margin = 0.05)

ggiraph - (giraffe)

Interactive Points (ggiraph)

In ggiraph you cannot transform a ggplot object but you have the same syntax, but put an _interactive on it.

Put a "Bird on It" Meme from Portlandia TV show

Interactive Points (ggiraph)

(g <- ggplot(cars, aes(wt, mpg)) +
    geom_point_interactive() +
    xlab("Weight (in tons)") + 
    ylab("Miles Per Gallon (MPG)") + 
    theme_bw(base_size = 22))

Need to girafe it?

girafe(ggobj = g)

ggiraph: No default tooltips

g <- ggplot(cars, aes(wt, mpg)) +
    geom_point_interactive(aes(tooltip = car)) +
    geom_line_interactive() +
    xlab("Weight (in tons)") + 
    ylab("Miles Per Gallon (MPG)") + 
    theme_bw(base_size = 22)
girafe(ggobj = g)

Highcharter - wrapper for Highcharts JS Library

Highcharter: Click away groups

cars %>% 
  hchart(
    "scatter",
    hcaes(x = hp, y = mpg, group = factor(cyl)))

Making a quick frequency data set

car_count = cars %>% 
  mutate(producer = ifelse(as.logical(am), "America", "Not America"),
         cylinders = factor(cyl)) %>%   
    group_by(producer, cylinders) %>% 
  summarise(
    hp = round(mean(hp), 2),
    n = dplyr::n()) %>% 
  group_by(producer) %>% 
  mutate(pct = n/sum(n)) %>% 
  ungroup()

Highcharter

car_count %>% 
  hchart(
    "bar",
    hcaes(y = hp, x = producer, group = cylinders)
  )

Highcharter Tile Map

Highcharter may come at a (literal) price

Highcharts offers both a commercial license as well as a free non-commercial license

Pricing Chart for Highcharts

rCharts: a JS widget interface

rCharts: Different Syntax

n1 <- car_count %>% 
  nPlot(n ~ producer, group = "cylinders", data = ., type = "multiBarChart")
n1$show('inline', include_assets = TRUE, cdn = TRUE)

rCharts: Scale to 100%

n2 <- car_count %>% 
  nPlot(pct ~ producer, group = "cylinders", data = ., type = "multiBarChart")
n2$show('inline', include_assets = TRUE, cdn = TRUE)

Remember Basic Figure Tenets

  • Show what you’re trying to show, stop making it too much

  • Hone in on the insights you found (don’t be too subtle)

  • You should be able to get the gist before you read anything

  • Make Labels Larger

  • Label Panels/Facets/Subplots (A, B, C, D)

  • Keep colors consistent if connected and distinct if not

  • Watch out for yellow with white text or on white background (projector)

  • Caption your figures

A Summary

  • Interactive graphics are sometimes powerful, but limited to HTML

  • Many different frameworks, customization ease is highly variable

  • Remember basic plotting tenets: show what you want to show, hone in on the insights (don’t be sutle

  • plotly good general framework, has a ggplot2 wrapper, but highcharts has some built in niceties.

Plotly can also work with crosstalk

Crosstalk: Shared Data is the Key

sd <- SharedData$new(quakes[sample(nrow(quakes), 100),])
# Use SharedData like a dataframe with Crosstalk-enabled widgets
bscols(
  leaflet(sd) %>% addTiles() %>% addMarkers(),
  datatable(sd, extensions="Scroller", style="bootstrap", class="compact", width="100%",
    options=list(deferRender=TRUE, scrollY=300, scroller=TRUE))
)

Making Connected Graphs are Hard

Conclusion

The purpose of visualization is insight, not pictures. ―Ben Shneiderman

Above all else, show the data. ―Edward Tufte